
/*
 * MegaMek -
 * Copyright (C) 2007 Ben Mazur (bmazur@sev.org)
 *  This program is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License as published by the Free
 *  Software Foundation; either version 2 of the License, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 *  for more details.
 */
package megamek.client.bot;

import java.util.Comparator;

import megamek.common.AmmoType;
import megamek.common.Compute;
import megamek.common.Mounted;
import megamek.common.ToHitData;
import megamek.common.WeaponType;

/**
 * The Class AttackOption.
 */
public class AttackOption extends ToHitData {

	/** some constant to remove magic number **/
    private static final int TWELVE = 12;
    /** some constant to remove magic number **/
	private static final double HUNDRED = 100.0;
	/** The Constant serialVersionUID. */
    private static final long serialVersionUID = -8566472187475019360L;

    /**
     * The Class Sorter.
     */
    static class Sorter implements Comparator<AttackOption> {
        /** The primary. */
        CEntity primary = null;

        /**
         * Instantiates a new sorter.
         *
         * @param primaryTarget the primary_target
         */
        public Sorter(final CEntity primaryTarget) {
            primary = primaryTarget;
        }

        /**
         * Comare see java compare.
         * @param a the attack option
         * @param a1 the attack option
         * @return int integer
         */
        public int compare(AttackOption a, AttackOption a1) {
            if (a.target.getKey().intValue() == a1.target.getKey().intValue()) {
                WeaponType w = (WeaponType) a.weapon.getType();
                WeaponType w1 = (WeaponType) a1.weapon.getType();
                if (w.getDamage() == WeaponType.DAMAGE_MISSILE) {
                    if (w1.getDamage() == WeaponType.DAMAGE_MISSILE) {
                        if (a.expected > a1.expected) {
                            return -1;
                        }
                        return 1;
                    }
                    return 1;
                } else if (w.getDamage() == WeaponType.DAMAGE_MISSILE) {
                    return -1;
                } else if (a.expected > a1.expected) {
                    return -1;
                } else {
                    return 1;
                }
            } else if (a.target.getKey().equals(primary.getKey())) {
                return -1;
            }
            return 1;
        }
    }

    /** The target. */
    public CEntity target;
    /** The value. */
    public double value;
    /** The weapon. */
    public Mounted weapon;
    /** The to hit. */
    public ToHitData toHit;
    /** The odds. */
    public double odds; // secondary odds
    /** The primaryOdds. */
    public double primaryOdds; // primary odds
    /** The heat. */
    public int heat;
    /** The expected. */
    public double expected; // damage adjusted by secondary to-hit odds
    /** The primaryExpected. */
    public double primaryExpected; // damage adjusted by primary to-hit odds
    /** The ammo left. */
    public int ammoLeft = -1; // -1 doesn't use ammo
    /** The useMode. */
    public String useMode = "None"; // The mode the weapon is set to for

    // this option

    // so it can be reloaded later
    /**
     * Instantiates a new attack option.
     *
     * @param pTarget the target
     * @param pWeapon the weapon
     * @param pValue the value
     * @param pToHit the to hit
     * @param pSecMod the sec_mod
     */
    public AttackOption(CEntity pTarget, Mounted pWeapon, double pValue,
            ToHitData pToHit, int pSecMod) {
        this.target = pTarget;
        this.weapon = pWeapon;
        this.toHit = pToHit;
        this.value = pValue;

        if (pTarget != null && pWeapon != null) {
            if (pWeapon.getType().getModesCount() > 0) {
                useMode = pWeapon.curMode().getName();
            }
            WeaponType w = (WeaponType) pWeapon.getType();

            // As a primary attack. Damage is already odds-adjusted.
            primaryOdds = Compute.oddsAbove(pToHit.getValue()) / HUNDRED;
            primaryExpected = this.value;

            // As a secondary attack. Raw damage is extracted, then adjusted
            // for secondary to-hit odds. Since units with active Stealth armor
            // cannot be secondary targets, chances of hitting are 0.

            if (pTarget.getEntity().isStealthActive()) {
                odds = 0.0;
            } else {
            	if (pSecMod <= TWELVE) {
            		odds = (Compute.oddsAbove(pToHit.getValue()
                        + pSecMod) / HUNDRED);
            	} else {
                    odds = 0.0;
            	}
            }
            heat = w.getHeat();
            expected = this.value / primaryOdds;
            expected = expected * odds;

            // Check for ammo; note that some conventional infantry and BA
            // weapons do NOT return AmmoType.T_NA

            final boolean isInfantryWeapon = w.hasFlag(WeaponType.F_INFANTRY);
            final boolean usesAmmo;
            if (!isInfantryWeapon & w.getAmmoType() != AmmoType.T_NA) {
                usesAmmo = true;
            } else {
            	usesAmmo = false;
            }
            final Mounted ammo;
            if (usesAmmo) {
            	ammo = pWeapon.getLinked();
            } else {
            	ammo = null;
            }
            if (usesAmmo && (ammo == null || ammo.getShotsLeft() == 0)) {
                this.value = 0.0; // should have already been caught...
                primaryExpected = 0.0;
                expected = 0.0;
            } else if (usesAmmo) {
                ammoLeft = ammo.getShotsLeft();
            }
        }
    }
}
